package top.vains.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import top.vains.entity.User;
import top.vains.exception.CustomerException;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * jwt加密解密工具类
 *
 * @author vains
 * @version 1.0
 * @since 2020/2/18 16:56
 **/
@Slf4j
public class JwtUtils {

    private JwtUtils () {}

    /**
     * 用户登陆成功之后生成token
     * 使用Hs256算法，私钥使用用户密码
     * @param ttlMillis 过期时间
     * @param user 用户信息
     * @return 返回token字符串
     */
    public static String createJwt(long ttlMillis, User user) {
        // 指定签名时使用的算法，也就是header部分，jjwt已经将这里封装好了
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        // 生成jwt的时间
        Date now = new Date(System.currentTimeMillis());
        // 创建payload的私有声明(根据特定的业务需要添加，如果用这个进行验证，一般要和接收方提前沟通好)
        Map<String, Object> map = new HashMap<>(3);
        map.put("userId", user.getUserId());
        map.put("number", user.getNumber());
        map.put("password", user.getPassword());
        // 生成签名时使用的密钥，严禁泄露，一般时本地配置文件
        String key = "123456";
        // 签发人   使用用户名
        String subject = user.getNumber();
        // 开始生成
        JwtBuilder builder = Jwts.builder()
                .setClaims(map)
                // 设置jwt的id，时jwt的唯一标识，根据业务需要，设置一个不重复的值，保证token的唯一性，从而避免重放攻击
                .setId(UUID.randomUUID().toString())
                // 设置签发时间
                .setIssuedAt(now)
                // 设置主体
                .setSubject(subject)
                // 设置签名的加密算法和密钥
                .signWith(signatureAlgorithm, key);
        if (ttlMillis > 0) {
            Date exp = new Date(System.currentTimeMillis() + ttlMillis);
            // 设置过期时间
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    /**
     * 检验token
     * @param token token字符串
     * @param user 用户信息
     * @return 返回检验结果
     */
    public static boolean isVerify(String token, User user) {
        try {
            // 得到 DefaultJwtParser
            Claims claims = parseJwt(token);
            String password = "password";
            if (claims.get(password).equals(user.getPassword())) {
                return true;
            }
        } catch (Exception e) {
            log.error("token验证失败，原因：", e);
            return false;
        }
        return false;
    }

    /**
     * 根据请求中的Token获取用户ID
     * @param request 请求对象
     * @return 返回用户ID
     */
    public static Integer getUserIdByToken(HttpServletRequest request) {
        Assert.notNull(request, "请求不能为空");
        String token = request.getHeader("Authorization");
        if (StringUtils.isEmpty(token)) {
            throw new CustomerException("登陆信息失效，请重新登陆！");
        }
        Claims claims = JwtUtils.parseJwt(token);
        return (Integer) claims.get("userId");
    }

    public static Claims parseJwt(String token) {
        return Jwts.parser()
                // 设置密钥
                .setSigningKey("123456")
                // 设置需要解析的token
                .parseClaimsJws(token).getBody();
    }

}
